package com.czh.framework.security.web.service;

import com.czh.common.constant.CacheConstants;
import com.czh.common.date.RedisCache;
import com.czh.common.domain.AjaxRes;
import com.czh.framework.exception.auth.ErrorMailException;
import com.czh.framework.security.web.RandomAuthCodeGenerator;
import com.czh.framework.security.web.UserDetailsEntity;
import com.czh.mail.service.IMailService;
import com.czh.service.entity.dto.LoginUserDto;
import com.czh.service.entity.dto.MailLoginDto;
import com.czh.service.entity.po.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static com.czh.common.constant.CacheConstants.*;

@Service
public class AuthService {

    public static final int CODE_LEN = 6;

    @Autowired
    AuthenticationManager authenticationManager;
    @Autowired
    RedisCache redisCache;

    @Autowired
    IMailService iMailService;
//    RedisTemplate redisTemplate;
    public String login(LoginUserDto loginUserDto) {

        UsernamePasswordAuthenticationToken uptoken = new UsernamePasswordAuthenticationToken(loginUserDto.getName(),loginUserDto.getPassword());


        //验证 会进行验证  执行 UserDetailServiceImpl取得用户 进行对比
        Authentication authenticate = authenticationManager.authenticate(uptoken);

        //如果验证成功会返回 一个成功的用户   失败 会报异常
        UserDetailsEntity loginUser = (UserDetailsEntity) authenticate.getPrincipal();

        String  cacheKey = UUID.randomUUID().toString();
        String redisKey = LOGIN_TOKEN_KEY_PREFIX + loginUser.getUsername() + ":" + cacheKey;
        loginUser.setRedisKey(redisKey);
        // TODO 可以判断是否 记住我 如果选择了记住我 则 时间长一点哦
        redisCache.setCacheObject(redisKey, loginUser,CacheConstants.TOKEN_TIME_OUT_MINUTE, TimeUnit.MINUTES);

        Map<String , Object> claims = new HashMap<>();
        claims.put(LOGIN_REDIS_KEY, redisKey);
        String token = TokenService.createToken(claims);

        return token;
    }

    public AjaxRes mailLogin(String to) {

        //TODO 查表 找到对应用户
        User user = new User("a","a","a");

        //TODO 注册
        if(user == null) {

            return AjaxRes.success();
        }

        try {

            //验证码 redis KEY
            String redisKey = MAIL_LOGIN_KEY_PREFIX + user.getName();

            //判断该用户是否已经整验证码了
            Object cacheObject = redisCache.getCacheObject(redisKey);
            if(cacheObject != null) {
                return AjaxRes.fault("已经有发送验证码请你等待");
            }

            String randomCode = RandomAuthCodeGenerator.getRandomCode(CODE_LEN);
            //TODO  修改为异步 发送邮箱
            new Thread(() -> iMailService.sendMail(to,"登陆验证","验证吗：" + randomCode)).start();
//            iMailService.sendMail(to,"登陆验证","验证吗：" + randomCode);

            redisCache.setCacheObject(redisKey,randomCode,300,TimeUnit.SECONDS);

            Map<String,Object> claims = new HashMap<>();
            claims.put(LOGIN_REDIS_KEY,redisKey);
            String token = TokenService.createToken(claims);
            AjaxRes success = AjaxRes.success();
            success.put("mailToken",token);
            success.put("username",user.getName());
            return success;
        }catch (Exception e) {
            throw new ErrorMailException("邮箱不存在哦");
        }
    }


    /**
     * 验证 邮箱
     * @param mailLoginDto
     * @return
     */
    public AjaxRes authenticateMailCode(MailLoginDto mailLoginDto) {
        String code = mailLoginDto.getCode();
        String mailToken = mailLoginDto.getMailToken();
        String username = mailLoginDto.getUsername();

        //TODO 查用户 username 权限啊 啥的
        UserDetailsEntity userDetails = new UserDetailsEntity();
        User user = new User();
        user.setName(username);
        userDetails.setUser(user);

        //解析token
        Map<String, Object> map = TokenService.parseToken(mailToken);
        String redisKey = (String) map.get(LOGIN_REDIS_KEY);
        String realCode = redisCache.getCacheObject(redisKey);

        //验证成功
        if (code.equals(realCode)) {

            String  cacheKey = UUID.randomUUID().toString();
            String _redisKey = LOGIN_TOKEN_KEY_PREFIX + userDetails.getUsername() + ":" + cacheKey;

            //用于用户推出登录
            userDetails.setRedisKey(_redisKey);

            redisCache.setCacheObject(_redisKey, userDetails,CacheConstants.TOKEN_TIME_OUT_MINUTE, TimeUnit.MINUTES);
            //生成token
            Map<String , Object> claims = new HashMap<>();
            claims.put(LOGIN_REDIS_KEY, _redisKey);
            String token = TokenService.createToken(claims);

            //TODO 统一格式
            AjaxRes success = AjaxRes.success();
            success.put(AjaxRes.KEY_TOKEN,token);
            return success;
        }

        return AjaxRes.fault("验证码错误");
    }


    public boolean logout() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserDetailsEntity logOutUser = (UserDetailsEntity)authentication.getPrincipal();
        return redisCache.deleteObject(logOutUser.getRedisKey());
    }
}
